home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / dviselect / search.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-16  |  4.4 KB  |  179 lines

  1. /*
  2.  * Copyright (c) 1987 University of Maryland Department of Computer Science.
  3.  * All rights reserved.  Permission to copy for any purpose is hereby granted
  4.  * so long as this copyright notice remains intact.
  5.  */
  6.  
  7. #ifndef lint
  8. static char rcsid[] = "$Header: search.c,v 1.1 88/02/11 17:08:55 jim Exp $";
  9. #endif
  10.  
  11. /*
  12.  * Key search routines (for a 32 bit key)
  13.  *
  14.  * SCreate initializes the search control area.
  15.  *
  16.  * SSearch returns the address of the data area (if found or created)
  17.  * or a null pointer (if not).  The last argument controls the disposition
  18.  * in various cases, and is a ``value-result'' parameter.
  19.  *
  20.  * SEnumerate calls the given function on each data object within the
  21.  * search table.  Note that no ordering is specified (though currently
  22.  * it runs in increasing-key-value sequence).
  23.  */
  24.  
  25. #include "types.h"
  26. #include "search.h"
  27.  
  28. #if vax || mc68000 || ns32000 || pyr
  29. #define    HARD_ALIGNMENT    4
  30. #else
  31. #define    HARD_ALIGNMENT    16    /* should suffice for most everyone */
  32. #endif
  33.  
  34. static int DOffset;        /* part of alignment code */
  35.  
  36. char    *malloc(), *realloc();
  37.  
  38. struct search *
  39. SCreate(dsize)
  40.     register unsigned int dsize;
  41. {
  42.     register struct search *s;
  43.  
  44.     if ((s = (struct search *) malloc(sizeof *s)) == 0)
  45.         return (0);
  46.  
  47.     if (DOffset == 0) {
  48. #ifndef HARD_ALIGNMENT
  49.         DOffset = sizeof(i32);
  50. #else
  51.         DOffset = (sizeof(i32) + HARD_ALIGNMENT - 1) &
  52.             ~(HARD_ALIGNMENT - 1);
  53. #endif
  54.     }
  55.     dsize += DOffset;    /* tack on space for keys */
  56.  
  57. #ifdef HARD_ALIGNMENT
  58.     /*
  59.      * For machines with strict alignment constraints, it may be
  60.      * necessary to align the data at a multiple of some positive power
  61.      * of two.  In general, it would suffice to make dsize a power of
  62.      * two, but this could be very space-wasteful, so instead we align it
  63.      * to HARD_ALIGNMENT.  64 bit machines might ``#define HARD_ALIGNMENT
  64.      * 8'', for example.  N.B.:  we assume that HARD_ALIGNMENT is a power
  65.      * of two.
  66.      */
  67.  
  68.     dsize = (dsize + HARD_ALIGNMENT - 1) & ~(HARD_ALIGNMENT - 1);
  69. #endif
  70.  
  71.     s->s_dsize = dsize;    /* save data object size */
  72.     s->s_space = 10;    /* initially, room for 10 objects */
  73.     s->s_n = 0;        /* and none in the table */
  74.     if ((s->s_data = malloc(s->s_space * dsize)) == 0) {
  75.         free((char *) s);
  76.         return (0);
  77.     }
  78.     return (s);
  79. }
  80.  
  81. /*
  82.  * We actually use a binary search right now - this may change.
  83.  */
  84. char *
  85. SSearch(s, key, disp)
  86.     register struct search *s;
  87.     register i32 key;
  88.     int *disp;
  89. {
  90.     register char *keyaddr;
  91.     int itemstomove;
  92.  
  93.     *disp &= S_CREATE | S_EXCL;    /* clear return codes */
  94.     if (s->s_n) {        /* look for the key */
  95.         register int h, l, m;
  96.  
  97.         h = s->s_n - 1;
  98.         l = 0;
  99.         while (l <= h) {
  100.             m = (l + h) >> 1;
  101.             keyaddr = s->s_data + m * s->s_dsize;
  102.             if (*(i32 *) keyaddr > key)
  103.                 h = m - 1;
  104.             else if (*(i32 *) keyaddr < key)
  105.                 l = m + 1;
  106.             else {    /* found it, now what? */
  107.                 if (*disp & S_EXCL) {
  108.                     *disp |= S_COLL;
  109.                     return (0);    /* collision */
  110.                 }
  111.                 *disp |= S_FOUND;
  112.                 return (keyaddr + DOffset);
  113.             }
  114.         }
  115.         keyaddr = s->s_data + l * s->s_dsize;
  116.     } else
  117.         keyaddr = s->s_data;
  118.  
  119.     /* keyaddr is now where the key should have been found, if anywhere */
  120.     if ((*disp & S_CREATE) == 0)
  121.         return (0);    /* not found */
  122.  
  123.     /* avoid using realloc so as to retain old data if out of memory */
  124.     if (s->s_space <= 0) {    /* must expand; double it */
  125.         register char *new;
  126.  
  127.         if ((new = malloc((s->s_n << 1) * s->s_dsize)) == 0) {
  128.             *disp |= S_ERROR;    /* no space */
  129.             return (0);
  130.         }
  131.         keyaddr = (keyaddr - s->s_data) + new;    /* relocate */
  132.         bcopy(s->s_data, new, s->s_n * s->s_dsize);
  133.         free(s->s_data);
  134.         s->s_data = new;
  135.         s->s_space = s->s_n;
  136.     }
  137.     /* now move any keyed data that is beyond keyaddr down */
  138.     itemstomove = s->s_n - (keyaddr - s->s_data) / s->s_dsize;
  139.     if (itemstomove) {
  140. #ifndef USE_BCOPY        /* often bcopy doesn't handle overlap */
  141.         register char *from, *to;
  142.  
  143.         from = s->s_data + s->s_n * s->s_dsize;
  144.         to = from + s->s_dsize;
  145.         while (from > keyaddr)
  146.             *--to = *--from;
  147. #else
  148.         bcopy(keyaddr + s->s_dsize, keyaddr + (s->s_dsize << 1),
  149.             itemstomove * s->s_dsize);
  150. #endif
  151.     }
  152.     *disp |= S_NEW;
  153.     s->s_n++;
  154.     s->s_space--;
  155.     *(i32 *) keyaddr = key;
  156.     keyaddr += DOffset;    /* now actually dataaddr */
  157.     /* the bzero is just a frill... */
  158.     bzero(keyaddr, s->s_dsize - DOffset);
  159.     return (keyaddr);
  160. }
  161.  
  162. /*
  163.  * Call function `f' for each element in the search table `s'.
  164.  */
  165. SEnumerate(s, f)
  166.     register struct search *s;
  167.     register int (*f)();
  168. {
  169.     register int n;
  170.     register char *p;
  171.  
  172.     n = s->s_n;
  173.     p = s->s_data;
  174.     while (--n >= 0) {
  175.         (*f)(p + DOffset, *(i32 *) p);
  176.         p += s->s_dsize;
  177.     }
  178. }
  179.